package config

import (
	"fmt"
	"gameServer/core/value"
	"os"
	"strconv"
	"strings"
	"time"
)

/* //* 环境变量配置实现，基于系统环境变量提供配置读写功能，支持多类型配置值转换，适配Config接口，通过前缀隔离避免配置冲突 */

/*

提供环境变量支持
功能说明：
- 实现基于系统环境变量的配置读写
- 支持多类型配置值转换，适配Config接口
- 按统一规则格式化环境变量键名（如前缀+大写+下划线替换点）
- 仅对当前进程有效，不支持持久化（Save）和配置监听（Watch）
*/

var env *EnvConfig

func init() {
	env = NewEnvConfig("GAME_")
}

// Get 获取指定键的环境变量值，支持设置默认值
// 工作逻辑：
//  1. 先通过 os.LookupEnv 检查环境变量是否存在；
//  2. 若存在，将值包装为 value.Value 实例返回（便于后续类型转换）；
//  3. 若不存在，使用传入的默认值（def）创建 value.Value 实例返回（默认值可省略，此时返回包装 nil 的实例）。
//
// 参数：
//
//	key - 环境变量的键（字符串类型，如 "PATH"、"APP_PORT"）
//	def - 可选参数，当环境变量不存在时使用的默认值（任意类型，最多传入1个，多余参数会被忽略）
//
// 返回值：
//
//	value.Value - 包装了环境变量值或默认值的实例，可通过其方法（如 Int()、String()）转换为目标类型
func Get(key string, def ...interface{}) value.Value {
	envKey := env.formatKey(key)
	// os.LookupEnv 用于查询环境变量：返回两个值，val 是环境变量的值（字符串），ok 是布尔值表示是否存在该环境变量
	if val, ok := os.LookupEnv(envKey); ok {
		// 若环境变量存在，调用 value.NewValue 包装该值为 Value 实例并返回
		// value.NewValue 接收任意类型参数，返回可进行多类型转换的 Value 接口实例
		return value.NewValue(val)
	}

	// 若环境变量不存在，使用默认值创建 Value 实例
	// def 是可变参数（...interface{}），允许传入0个或1个参数：
	// - 若传入1个参数，使用该参数作为默认值；
	// - 若未传入参数，def 为空切片，此时 value.NewValue 会创建包装 nil 的实例
	return value.NewValue(def...)
}

// Set 设置环境变量的值
// 工作逻辑：直接调用 os.Setenv 底层方法设置环境变量，将键值对写入当前进程的环境变量中
// 参数：
//
//	key - 环境变量的键（字符串类型，如 "LOG_LEVEL"）
//	value - 环境变量的值（字符串类型，环境变量的值本质都是字符串，后续解析需手动处理类型）
//
// 返回值：
//
//	error - 操作错误（如权限不足无法设置，或 key 包含无效字符等，成功时返回 nil）
func Set(key string, v interface{}) error {
	envKey := env.formatKey(key) // 格式化键名（如"debug.mode"→"GAME_DEBUG_MODE"）

	// 类型断言：若value本身是string类型，直接使用
	if str, ok := v.(string); ok {
		return os.Setenv(envKey, str) // 调用os.Setenv设置环境变量
	} else {
		// 非string类型：用fmt.Sprintf转为字符串（如int 8081→"8081"，bool true→"true"）
		return os.Setenv(envKey, fmt.Sprintf("%v", v))
	}
	// os.Setenv 用于设置环境变量，接收键和值两个字符串参数，成功返回 nil，失败返回具体错误
}

// Del 删除指定键的环境变量
// 工作逻辑：调用 os.Unsetenv 底层方法移除环境变量，使该键在当前进程中不再存在
// 参数：
//
//	key - 要删除的环境变量的键（字符串类型）
//
// 返回值：
//
//	error - 操作错误（极少数情况会出错，如 key 格式无效，成功时返回 nil）
func Del(key string) error {
	key = env.formatKey(key)
	// os.Unsetenv 用于删除环境变量，接收键字符串参数，成功返回 nil
	return os.Unsetenv(key)
}

// Has 检查指定键的环境变量是否存在
// 工作逻辑：通过 os.LookupEnv 查询环境变量，返回其存在性标识（忽略具体值）
// 参数：
//
//	key - 要检查的环境变量的键（字符串类型）
//
// 返回值：
//
//	bool - 存在返回 true，不存在返回 false
func Has(key string) bool {
	// 调用 os.LookupEnv 获取存在性标识 ok，忽略具体值 val
	key = env.formatKey(key)
	_, ok := os.LookupEnv(key)
	return ok
}

// EnvConfig 环境变量配置结构体：基于系统环境变量实现Config接口
type EnvConfig struct {
	prefix string // 环境变量键名前缀（用于隔离不同组件的配置，如"GAME_"）
}

/*
prefix 的核心作用：比如两个组件都有server.port配置，给组件 A 加前缀A_、组件 B 加前缀B_，最终环境变量会变成A_SERVER_PORT和B_SERVER_PORT，避免冲突
*/

// NewEnvConfig 创建环境变量配置实例
//
// 参数：prefix 环境变量键名前缀（如"GAME_"，空字符串表示无前缀）
// 返回：*EnvConfig 初始化后的环境变量配置实例
func NewEnvConfig(prefix string) *EnvConfig {
	return &EnvConfig{
		prefix: prefix,
	}
}

// 获取环境变量值（环境变量目前使用的是一些键值对的获取）
func (e *EnvConfig) Get(key string) interface{} {
	envKey := e.formatKey(key)
	return os.Getenv(envKey) // 通过键获取环境变量值（获取以后都是字符串，需要进行对应的转换）
}

// 获取字符串环境变量值
func (e *EnvConfig) GetString(key string) string {
	envKey := e.formatKey(key)
	return os.Getenv(envKey)
}

// 获取正数环境变量值
func (e *EnvConfig) GetInt(key string) int {
	envKey := e.formatKey(key)
	value := os.Getenv(envKey)
	if value == "" {
		return 0
	}
	intValue, err := strconv.Atoi(value)
	if err != nil {
		return 0
	}
	return intValue
}

// 获取不二环境变量值
func (e *EnvConfig) GetBool(key string) bool {
	envKey := e.formatKey(key)
	value := os.Getenv(envKey)
	if value == "" {
		return false
	}
	boolValue, err := strconv.ParseBool(value)
	if err != nil {
		return false
	}
	return boolValue
}

// GetFloat 获取浮点数环境变量值
func (e *EnvConfig) GetFloat(key string) float64 {
	envKey := e.formatKey(key)
	value := os.Getenv(envKey)
	if value == "" {
		return 0
	}
	floatValue, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return 0
	}
	return floatValue
}

// GetDuration 获取时间间隔环境变量值
func (e *EnvConfig) GetDuration(key string) time.Duration {
	envKey := e.formatKey(key)
	value := os.Getenv(envKey)
	if value == "" {
		return 0
	}
	duration, err := time.ParseDuration(value)
	if err != nil {
		return 0
	}
	return duration
}

// GetStringSlice 获取字符串切片环境变量值
func (e *EnvConfig) GetStringSlice(key string) []string {
	envKey := e.formatKey(key)
	value := os.Getenv(envKey)
	if value == "" {
		return nil
	}
	return strings.Split(value, ",")
}

// GetMap 获取Map环境变量值（环境变量不支持复杂Map结构）
func (e *EnvConfig) GetMap(key string) map[string]interface{} {
	return nil
}

// GetMapString 获取字符串Map环境变量值（环境变量不支持复杂Map结构）
func (e *EnvConfig) GetMapString(key string) map[string]string {
	return nil
}

// Set 设置环境变量值：仅对当前进程有效（进程退出后失效，不持久化）
//
// 参数：key 用户定义的键名（如"debug.mode"）；value 要设置的值（任意类型）
func (e *EnvConfig) Set(key string, value interface{}) {
	envKey := e.formatKey(key) // 格式化键名（如"debug.mode"→"GAME_DEBUG_MODE"）

	// 类型断言：若value本身是string类型，直接使用
	if str, ok := value.(string); ok {
		os.Setenv(envKey, str) // 调用os.Setenv设置环境变量
	} else {
		// 非string类型：用fmt.Sprintf转为字符串（如int 8081→"8081"，bool true→"true"）
		os.Setenv(envKey, fmt.Sprintf("%v", value))
	}
	//仅对当前进程有效：设置的环境变量不会影响系统全局，也不会写入配置文件，进程退出后失效；
}

// formatKey 格式化键名：将用户传入的key转为标准环境变量格式
//
// 参数：key 用户定义的键名（如"server.port"）
// 返回：string 格式化后的环境变量键名（如"GAME_SERVER_PORT"）
func (e *EnvConfig) formatKey(key string) string {
	// 处理前缀：若有前缀，在前缀和key之间加下划线（如"GAME" + "_" + "server.port"）
	// 替换分隔符：将key中的"."替换为"_"（如"server.port"→"server_port"）
	// 转大写：将整个键名转为全大写（如"server_port"→"SERVER_PORT"）
	if e.prefix == "" {
		return strings.ToUpper(strings.ReplaceAll(key, ".", "_"))
	}
	return strings.ToUpper(e.prefix + "_" + strings.ReplaceAll(key, ".", "_"))
}

// 环境变量变量配置不支持watch和save等方法
func (e *EnvConfig) Watch(key string, callback func(value interface{})) error {
	// 环境变量不支持监听
	return nil
}

func (e *EnvConfig) Unwatch(key string) error {
	// 环境变量不支持监听
	return nil
}

func (e *EnvConfig) Load() error {
	// 环境变量不需要显式加载
	return nil
}

func (e *EnvConfig) Save() error {
	// 环境变量不支持保存到持久化存储
	return nil
}
